package com.iot.inclinometer.util;

import android.util.Log;

import com.google.gson.Gson;
import com.iot.inclinometer.pojo.ResponseDataDTO;
import com.iot.inclinometer.pojo.ResponseDataStatusEnum;
import com.iot.inclinometer.pojo.SendDataDTO;
import com.xuhao.didi.core.pojo.OriginalData;
import com.xuhao.didi.core.protocol.IReaderProtocol;
import com.xuhao.didi.socket.client.sdk.OkSocket;
import com.xuhao.didi.socket.client.sdk.client.ConnectionInfo;
import com.xuhao.didi.socket.client.sdk.client.action.SocketActionAdapter;
import com.xuhao.didi.socket.client.sdk.client.connection.IConnectionManager;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.charset.Charset;
import java.util.Vector;

public class TCPClientReceiver extends SocketActionAdapter {
    private final static String TAG = TCPClientReceiver.class.getSimpleName();

    private TCPClient tcpClient;
    /**
     * 最多重连失败次数，就断开
     */
    private int MAX_FAILED_COUNT = 5;
    private volatile int currentFailedCount = 0;


    public Vector<SendDataDTO> getSendDataDTO() {
        return sendDataDTOList;
    }

    public void setSendDataDTO(Vector<SendDataDTO> sendDataDTOList) {
        this.sendDataDTOList = sendDataDTOList;
    }

    /**
     * 要发送数据对象
     */
    private volatile Vector<SendDataDTO> sendDataDTOList;

    public TCPClientReceiver() {
        this(null, null);
    }

    public TCPClientReceiver(Vector<SendDataDTO> sendDataDTOList) {
        this(sendDataDTOList, null);
    }

    public TCPClientReceiver(Vector<SendDataDTO> sendDataDTOList, TCPClient tcpClient) {
        this.tcpClient = tcpClient;
        this.sendDataDTOList = sendDataDTOList;
    }

    @Override
    public void onSocketConnectionSuccess(ConnectionInfo info, String action) {
        String msg = String.format("连接[%s:%d]成功!", info.getIp(), info.getPort());
        Log.i(TAG, msg);
        currentFailedCount = 0;
        this.tcpClient.sendConnOkMessage("【提示】连接服务器成功!");

        this.sendData();
    }

    private void sendData() {
        String msg = "【提示】当前无数据需要发送";
        if (this.sendDataDTOList == null || this.sendDataDTOList.isEmpty()) {
            this.tcpClient.sendMessage(msg);
            return;
        }
        boolean flag = false;
        for (SendDataDTO sendDataDTO : this.sendDataDTOList) {
            if (sendDataDTO.getUploaded() < 1) {
                this.tcpClient.getSocketConnManager().send(sendDataDTO);
                flag = true;
            }
        }
        if (flag) {
            msg = "【提示】发送数据完成,等待服务器响应......";
        }
        this.tcpClient.sendMessage(msg);
    }

    private void updataSendDataStatus(String id, int status) {
        if (this.sendDataDTOList == null || this.sendDataDTOList.isEmpty()) {
            return;
        }
        for (SendDataDTO sendDataDTO : this.sendDataDTOList) {
            if (sendDataDTO.getIdentity().equals(id)) {
                sendDataDTO.setUploaded(status);
                break;
            }

        }
    }

    private boolean hasAllSuccess() {
        boolean f = true;
        if (this.sendDataDTOList == null || this.sendDataDTOList.isEmpty()) {
            return f;
        }
        for (SendDataDTO sendDataDTO : this.sendDataDTOList) {
            if (sendDataDTO.getUploaded() < 0) {
                f = false;
                break;
            }
        }
        return f;
    }

    @Override
    public void onSocketConnectionFailed(ConnectionInfo info, String action, Exception e) {
        String msg = String.format("连接[%s:%d]失败! >> %s", info.getIp(), info.getPort(), e.getLocalizedMessage());

        Log.e(TAG, msg);

        if (this.tcpClient != null) {
            this.tcpClient.sendConnFailedMessage("【错误】连接服务器失败!");
        }

        if (++currentFailedCount >= MAX_FAILED_COUNT) {
            if (this.tcpClient != null) {
                this.tcpClient.disconnect();
            }
            return;
        }

    }

    @Override
    public void onSocketIOThreadShutdown(String action, Exception e) {
        super.onSocketIOThreadShutdown(action, e);
        Log.i(TAG, "IO Thread shutdown");
        currentFailedCount = 0;
    }


    @Override
    public void onSocketReadResponse(ConnectionInfo info, String action, OriginalData data) {
        //遵循以上规则,这个回调才可以正常收到服务器返回的数据,数据在OriginalData中,为byte[]数组,
        // 该数组数据已经处理过字节序问题,直接放入ByteBuffer中即可使用
//        String body = new String(src, Charset.forName("UTF-8"));

//        String body =  Charset.forName("UTF-8").decode(ByteBuffer.wrap(data.getBodyBytes()).asReadOnlyBuffer()).toString();

        String body = new String(data.getBodyBytes(), Charset.forName("UTF-8"));
        Log.d(TAG, String.format("收到服务器响应: >> %s", body));
        Gson res = new Gson();
        ResponseDataDTO responseDataDTO;
        String msg = "";
        try {
            responseDataDTO = res.fromJson(body, ResponseDataDTO.class);

            int status = responseDataDTO.getStatus();

            if (status == ResponseDataStatusEnum.OK.getCode()) {
                msg = "【提示】上传数据" + ResponseDataStatusEnum.OK.getName();

                this.updataSendDataStatus(responseDataDTO.getDataIdentity(), 1);

            } else {
                msg = String.format("【错误】上传数据%s: >> %s", ResponseDataStatusEnum.FAILED.getName(), responseDataDTO.getMsg());
            }

            Log.d(TAG, msg);
        } catch (Exception e) {
            msg = String.format("【错误】服务器响应数据格式错误: >> %s", body);
            Log.d(TAG, msg);
        } finally {
            if (this.tcpClient == null) {
                IConnectionManager cm = OkSocket.open(info);
                if (cm != null && cm.isConnect()) {
                    cm.disconnect();
                }
            } else {
                this.tcpClient.sendMessage(msg);
                if (this.hasAllSuccess()) {
                    this.tcpClient.disconnect();
                    this.tcpClient.sendClosedMessage("【提示】服务器连接已关闭");
                }
            }
        }

    }


    public static class TCPClientReaderProtocol implements IReaderProtocol {

        @Override
        public int getHeaderLength() {
            /*
             * 返回不能为零或负数的报文头长度(字节数)。
             * 您返回的值应符合服务器文档中的报文头的固定长度值(字节数),可能需要与后台同学商定
             */
            return 4;/*固定报文头的长度(字节数)*/
        }

        @Override
        public int getBodyLength(byte[] header, ByteOrder byteOrder) {
            /*
             * 体长也称为有效载荷长度，
             * 该值应从作为函数输入参数的header中读取。
             * 从报文头数据header中解析有效负载长度时，最好注意参数中的byteOrder。
             * 我们强烈建议您使用java.nio.ByteBuffer来做到这一点。
             * 你需要返回有效载荷的长度,并且返回的长度中不应该包含报文头的固定长度
             */

            /*有效负载长度(字节数)，固定报文头长度(字节数)除外*/
            ByteBuffer bb = ByteBuffer.wrap(header).order(byteOrder);
            return bb.getInt();
//            return Integer.parseInt(new String(header));// 字符串回传
        }
    }
}
